from typing import Generator, Iterable
from docx.opc.exceptions import PackageNotFoundError
import os
import zipfile
from MelodieFuncFlow import MelodieGenerator, MelodieFrozenGenerator
import tornado

from ..api import FILE_OPEN_HANDLER

from ..models import Finding

from ..app.configs import AppConfig
from ..utils import basename, BackgroundTask
from ..config import dump_document, iter_documents_in_folder, iter_documents_info
from ..indexing import SUPPORTED_EXTENSIONS, TEXT_EXTRACTORS, AlreadyIndexed

from .base import BaseWebSocketHandler, BaseWebSocketContext


def index():
    documents = (
        MelodieGenerator(AppConfig().docs_indexing_paths)
        .map(
            lambda path: (
                iter_documents_in_folder(path)
                .filter(
                    lambda doc: (not basename(doc).startswith("~$"))
                    and doc.endswith(SUPPORTED_EXTENSIONS)
                )
                .l
            )
        )
        .reduce(lambda x, y: x + y, [])
    )
    docs_num = MelodieFrozenGenerator(documents).len
    print("docs_num ", docs_num)
    for i, doc in enumerate(documents):
        # self.progress_bar["value"] = ((i + 1) / docs_num) * 100
        print(i, docs_num, doc)
        yield i, docs_num, doc
        # self.label.config(text=f"正在分析 {i+1}/{docs_num}: {basename(doc)}")
        ext = os.path.splitext(doc)[1]
        try:
            info = TEXT_EXTRACTORS[ext](doc)
            info.to_json()
            dump_document(info)
        except KeyError:
            import traceback

            traceback.print_exc()
        except OSError:
            import traceback

            traceback.print_exc()
        except AlreadyIndexed:
            print("skipped!")
            continue
        except ValueError:
            continue
        except (PackageNotFoundError, zipfile.BadZipFile):
            import traceback

            traceback.print_exc()


def text_match(para: str, words: Iterable[str]) -> bool:
    for word in words:
        if para.lower().find(word.lower()) == -1:
            return False
    return True


def search(text: str) -> MelodieGenerator[Finding]:
    def _():
        if text.strip() == "":
            return
        search_words = [word.strip() for word in text.split(" ") if word.strip() != ""]
        # findings = []
        for doc_info in iter_documents_info():
            paragraphs = (
                MelodieFrozenGenerator(doc_info.paragraphs)
                .filter(lambda para: text_match(para, search_words))
                .l
            )
            table_contents = (
                MelodieFrozenGenerator(doc_info.tables)
                .map(
                    lambda table: (
                        MelodieGenerator(table.cells)
                        .filter(lambda cell: text_match(cell.text, search_words))
                        .map(lambda cell: cell.text)
                        .l
                    )
                )
                .reduce(lambda a, b: a + b, [])
            )

            if len(paragraphs) + len(table_contents) > 0:
                yield (Finding(doc_info, paragraphs + table_contents))

    return MelodieGenerator(_())


# 定义WebSocket处理类
class TextIndexingWebSocketHandler(BaseWebSocketHandler):
    def on_open(self):
        self.index_iterator = index()
        self.task = BackgroundTask(
            "index_docs",
            self.index_loop,
            (),
            on_finish=self.handle_finish,
        )
        self.task.run()
        # self.ctx.send_message({"type": "initial", "data": })

    def index_loop(self):
        print("Starting indexing loop")
        for i, docs_num, doc_file in self.index_iterator:
            self.ctx.send_message(
                {
                    "type": "update",
                    "data": {
                        "analysed_docs": i + 1,
                        "docs_num": docs_num,
                        "doc_file": doc_file,
                    },
                }
            )

    def handle_finish(self):
        pass
        # self.ctx.close()


# 定义WebSocket处理类
class TextSearchingWebSocketHandler(BaseWebSocketHandler):
    def on_open(self, text):
        self.search_iterator = search(text)
        # TODO: 增加记忆功能，断开重连也能update
        self.task = BackgroundTask(
            "search_docs",
            self.search_loop,
            (),
            on_finish=self.handle_finish,
        )

        self.task.run()
        self.ctx.send_message({"type": "initial", "data": {"findings": []}})

    def search_loop(self):
        print("Starting indexing loop")
        for i, finding in enumerate(self.search_iterator):
            self.ctx.send_message({"type": "update", "data": finding.to_dict()})
        self.ctx.send_message({"type": "status", "data": {"status": "finish"}})

    def handle_finish(self):
        pass


def open_file(file: str, text: str, search: str):
    """
    使用指定的打开方式打开文件
    """
    text = text if len(text) <= 30 else text[:30]
    ext = os.path.splitext(file)[1]
    return FILE_OPEN_HANDLER[ext](file, text)
